/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package app;

import GUI.AppFrame;
import GUI.ControlListener;
import GUI.OptionsFrame;
import comlink.MySocket;



import java.awt.event.*;
import java.beans.EventHandler;
import java.io.*;
import java.util.EventListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javabluetoothserial.JavaBluetoothSerial;
import javax.swing.JOptionPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
 * Controleur principal de l'application. Enregistre les changements issus de la connection bluetooth, écrit dans cette dernière, et modifie la Frame en conséquence.
 * @author isen
 */
public class FrameController {
    
    Preferences prefs = Preferences.systemNodeForPackage(FrameController.class);
    AppFrame frame;
    
    private boolean writingRun;
    private int distance;
    private int speed;
    private int slope;
    private int totalPower;
    private double totalEnergy = 0.0;
    private double userEnergySpeedSensor = 0;
    private double userEnergyTorqueSensor = 0;
    private JavaBluetoothSerial btServer;
    Thread writingThread;
    private boolean autoReconnect= true;
    WindowListener wl ;
    ChangeListener cl;
    ActionListener al;
    boolean testMode = prefs.getBoolean("testMode", false);
    
    MySocket tcpSocket;
   

//<editor-fold defaultstate="collapsed" desc=" setters declaration">
    /**
     * 
     * @param parseInt
     */
    public void setSlope(int parseInt) {
        this.slope = parseInt;
        frame.setSlope(slope);
        setPower();
    }
    
        private void setPower() {
            if ((tcpSocket == null || !this.tcpSocket.isConnected()) && !testMode){
                System.out.println("error!");
                frame.setCaptorsDisconnected();
                JOptionPane.showMessageDialog(frame,"Non connecté aux capteurs. \nconnectez les capteurs ou activez le mode test");
                return;
            }
        double cfm = prefs.getDouble("cfm", 0.004), cfa = prefs.getDouble("cfa", 0.3), m = prefs.getInt("weight", 90), g=9.8;
        double msSpeed = (1/3.6)*(double)speed ;
        totalPower = (int) (g*m*(((double)slope)*0.01*(msSpeed)) 
                + cfa*(Math.pow((msSpeed), 3)) 
                + g*m*cfm*(msSpeed));
        frame.setTotalPower(totalPower);
        frame.setUserPower(getuserPowerSpeedSensor());
        frame.setTorquePower(getuserPowerTorqueSensor());
        if(!testMode){
            
            sendRequiredPower(totalPower);
        }
        
    }
    
        /**
         * 
         */
        public void setEnergy(){
        //System.out.println("energy = "+energy);
        if (speed == 0) return;
        if (totalPower >10){
        Double doublePower = (double)totalPower;
        Double doubleSpeed = ((double)speed)*1000;    
        totalEnergy = totalEnergy + doublePower/doubleSpeed;
        }else {
            Double doubleSpeed = ((double)speed)*1000;
            totalEnergy = totalEnergy + 10/doubleSpeed;
        }
        frame.setTotalEnergy(totalEnergy);
        
        
        Double doubleUserPower = (double)getuserPowerSpeedSensor();
        Double doubleSpeed = ((double)speed)*1000;    
        userEnergySpeedSensor = userEnergySpeedSensor + doubleUserPower/doubleSpeed;
        frame.setUserEnergy(userEnergySpeedSensor);
        
        
        doubleUserPower = (double)getuserPowerTorqueSensor();
        userEnergyTorqueSensor = userEnergyTorqueSensor + doubleUserPower/doubleSpeed;
        frame.setTorqueEnergy(userEnergyTorqueSensor);
        
    }
    /**
     * 
     * @param speed
     */
    public void setSpeed(int speed) {
        this.speed = speed;
        setPower();
    }
    
    /**
     * 
     * @param distance
     */
    public void setDistance(int distance) {
        this.distance = distance;
        this.frame.setDistance(distance);
    }
     
    /**
     * 
     */
    public void incrementDistance() {
        this.distance++;
    }
         


    
    
    

    
//</editor-fold>
    
//<editor-fold defaultstate="collapsed" desc=" getters declaration">
         /**
          * 
          * @return
          */
         public int getDistance() {
        return distance;
    }
    
        
         /**
          * 
          * @return
          */
         public int getSpeed() {
        return speed;
    }
//</editor-fold>
   


//<editor-fold defaultstate="collapsed" desc=" constructors">

    
         /**
          * Default constructor
          */
         public FrameController(){
        
        ControlListener cl = new ControlListener(){

            @Override
            public void onClose() {
                autoReconnect = false;
                btServer.close();
            }

            @Override
            public void speedChange() {
                setSpeed(frame.speedChanged());
            }

            @Override
            public void openOptionsPane() {
                
               
                OptionsFrame options = new OptionsFrame(prefs);
            }
            
        };    
        System.out.println("mode test:"+testMode);    
        this.frame = new AppFrame(cl, prefs);
        
        
        
                
        btServer = new JavaBluetoothSerial(this);
        try {
            btServer.startServer();
        } catch (IOException ex) {
            Logger.getLogger(FrameController.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        sender();
        
        if (!testMode){
            connectToCaptors();
        }
    }
    //</editor-fold>
 
         
         
    /**
     * 
     * Methode créant un Thread qui gérera les données sortantes, ainsi que les modifications qu'aura a faire la Frame en conséquence.
     */     
    private void sender(){
      
        writingThread = new Thread(){
        
            
            @Override
            public void run() {
                writingRun = true;
                while(writingRun){
                    try {
                        
                        
                        btServer.write("movement:"+Integer.toString(distance)+","+totalEnergy+","+userEnergySpeedSensor+","+userEnergyTorqueSensor);
                        setDistance(distance);
                        setEnergy();
                        //System.out.println("distance : "+distance );
                        
                    if(this.isInterrupted())return;
                     if (speed !=0){
                        incrementDistance();                  
                        Thread.sleep((long)3600/speed);
                   
                    
                     }else{
                         Thread.sleep(1000);
                     }
                      } catch (InterruptedException ex) {
                        Logger.getLogger(FrameController.class.getName()).log(Level.SEVERE, null, ex);
                        
                        return;
                    } catch (IOException ex) {
                        
                        reconnect();
                        return;
                    }
                }
            }

            
            
        };
        writingThread.start();
    }
    
    
    
    private void reconnect(){
        if(!autoReconnect) return;
            
        writingRun = false;
        this.btServer.close();
        if (this.testMode == false && this.tcpSocket != null)this.tcpSocket.close();
        if (writingThread != null){
            writingThread.interrupt();
        
        writingThread = null;
        }
        
            try {
                this.btServer.startServer();
                if (this.testMode == false)this.connectToCaptors();
            } catch (IOException ex) {
                Logger.getLogger(FrameController.class.getName()).log(Level.SEVERE, null, ex);
            }
        sender();
        
        
        
        
        
    }

    /**
     * Send to the Android requesting app the data it needs to work properly
     */
    public void sendSlopesData() {
        System.out.println("Sending slopes data to app request");
        Thread slopesSender = new Thread(){

            @Override
            public void run() {
                String path ;
                int i = 1;
                path = prefs.get(OptionsFrame.SLOPES_ACCESS_PATH+i, null);
                i++;
                while(path != null){
                    try {
                        BufferedReader bReader = new BufferedReader(new FileReader(new File(path)));
                        //server.write("transmitData.slopeData:debutFichier");
                         //System.out.println("transmitData.slopeData:finFichier");
                         while(bReader.ready()){
                             btServer.write("transmitData.slopeData:"+bReader.readLine());
                             //System.out.println("transmitData.slopeData:"+bReader.readLine());
                         }
                         
                    } catch (IOException ex){
                        Logger.getLogger(FrameController.class.getName()).log(Level.SEVERE, null, ex);
                        
                    } 
       
                path = prefs.get(OptionsFrame.SLOPES_ACCESS_PATH+i, null);
                i++;
                
                
                
                }
                try {
                    btServer.write("transmitData.slopeData:finTransmission");
                } catch (IOException ex) {
                    Logger.getLogger(FrameController.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            
        };
        
        slopesSender.start();
    }

    
    private int getuserPowerSpeedSensor(){
        if (totalPower <= 0) return 0;
        if (totalPower<50)return totalPower;
        if (totalPower<300)return 50;
        if (this.speed<=25) return (totalPower-250);
        return totalPower;
    }
    private int getuserPowerTorqueSensor(){
        if(totalPower<=0) return 0;
        if (this.speed<=25 && totalPower<500) return (totalPower/2);
        if (this.speed<=25) return totalPower - 250;
        return totalPower;
    }

    /**
     * 
     */
    public void reset() {
        distance = 0;
        slope = 0;
        this.totalEnergy = 0;
        this.userEnergySpeedSensor = 0;
        this.userEnergyTorqueSensor = 0;
    }

    public void sendPreferences() {
        System.out.println("sending preferences");
        try {
            btServer.write("transmitData.preferences.max:"+prefs.get("maxTime", "-1"));
            btServer.write("transmitData.preferences.penteNegative:"+prefs.get("negSlope", "-20"));
            
            btServer.write("transmitData.preferences.pentePositive:"+prefs.get("posSlope", "20"));
            btServer.write("transmitData.preferences.contenuLegal:"+prefs.get("legalContent", "2012 tous droits réservés"));
        
        } catch (IOException ex) {
            Logger.getLogger(FrameController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void writeName(String read) {
        System.out.println("writing");
        
            File file = new File(prefs.get("contactsDirectory", "D://Documents//contacts.txt"));
        try {
            file.createNewFile();
        
            BufferedWriter bWriter = new BufferedWriter(new FileWriter(file,true)); 
                read = read.substring(read.indexOf(":")+1);
                bWriter.write(read.substring(0, read.indexOf(" prenom:"))+"\t");
                read = read.substring(read.indexOf(":")+1);
                bWriter.write(read.substring(0, read.indexOf(" adresseMail:"))+"\t");
                read = read.substring(read.indexOf(":")+1);
                bWriter.write(read+"\n");
                bWriter.flush();
                System.out.println("wrote line");
            } catch (IOException ex) {
            Logger.getLogger(FrameController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void connectToCaptors() {
        System.out.println("connecting to the captors interface");
        tcpSocket = new MySocket(6789){

            @Override
            public void receivedData(String line) {
                frame.setCaptorsConnected();
                if (line.startsWith("speed:")){
                    receivedNewSpeed(Integer.parseInt(line.substring(6)));
                }
            }
            
        };
        
    }
    
    private void receivedNewSpeed(int speed){
        this.setSpeed(speed);
    }
    private void sendRequiredPower(int power){
        if (tcpSocket.isConnected()){
            tcpSocket.sendData("power:"+power);
        }
    }


    
}
